﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */
#include "BurnCtrl3X.h"
#include <QMessageBox>
#include <QDateTime>
#include <QDir>
#include <QCryptographicHash>
#include <QTextCodec>
#include "SecureLink/Channel.h"
#include "Burn.h"

namespace  {
    const int NUMBER_VALUE_TWO = 2;
    const int NUMBER_ONE_HUNDRED = 100;
    const int TIMEOUT_30S = 30000;
    const int SLEEP_1S = 1000;
    const int SLEEP_1500 = 1500;
    const int DEFAULT_PER_PACKET_SIZE = 4096;
}

QMap<unsigned long long, BurnCtrl3XClass::BurnCtrl3X *> BurnCtrl3XClass::BurnCtrl3X::myCtrlMap;
BurnCtrl3XClass::BurnCtrl3X::BurnCtrl3X(ChipType type, QObject *parent) : BurnCtrl(type, parent),
    currentlyBurnName(""),
    comHandle(0),
    currentlyBurnSize(0),
    isBurnStart(false),
    mutex(new QMutex())
{
    isResetAfterSuccess = true;
    isOpen = false;
    infoArrayDlg.clear();
    independent = true;
    sendBurnTimeout = TIMEOUT_30S;
    RegisterCallback(SetTextEditReceivePrint, nullptr, SetProgress);
}

BurnCtrl3XClass::BurnCtrl3X::~BurnCtrl3X()
{
    if (mutex != nullptr) {
        delete mutex;
        mutex = nullptr;
    }
}

void BurnCtrl3XClass::BurnCtrl3X::StartConnect()
{
    if (com <= 0) {
        emit SignalOpenComFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        return;
    }
    SetChipType(0x30002);
    QString comStr = "COM" + QString::number(com);
    comHandle = OpenSerialPort(comStr.toLatin1(), baud, Global::Stopbits2Int(stopbits), Global::Parity2Int(parity));
    if (comHandle == 0) {
        emit SignalOpenComFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        RemoveTempDir();
        isFirstBurnStart = true;
        return;
    }
    emit SignalSetProgressRange(0, SHRT_MAX);
    SetIsCancel(FALSE);
    SetIsReady(comHandle, true);
    myCtrlMap.insert(comHandle, this);
    comHandleMap.insert(comHandle, false);
    operatorType = OperatorType::OPERATOR_TYPE_BURN;
    isOpen = true;
    if (isMultipleBurn) {
        SetHandshakeTimeout(comHandle, -1);
    } else {
        SetHandshakeTimeout(comHandle, sendBurnTimeout);
    }
    QString log = tr("Connecting...Reset the device...\n");
    SetResult(ERR_WAITING);
    OutputString(log);
    StartConnectSub();
}

bool BurnCtrl3XClass::BurnCtrl3X::InnerStartConnectSub()
{
    for (int i = 0; i < infoArray.size(); i++) {
        isBurnStart = false;
        if (isCancel == TRUE) {
            mutex->lock();
            if (comHandle != 0) {
                DestroyDevice(comHandle);
                comHandle = 0;
                myCtrlMap.remove(comHandle);
            }
            mutex->unlock();
            emit SignalBurnFileFailed();
            currentlyBurnSize = 0;
            isOpen = false;
            OneTimeBurnQuit(ERR_FAILURE);
            RemoveTempDir();
            return false;
        }
        if (i != 0 && isMultipleBurn) {
            SetHandshakeTimeout(comHandle, sendBurnTimeout);
        }
        currentlyBurnName = infoArray[i].fileName;
        BOOL ret = TRUE;
        if (modemPacketSize < DEFAULT_PER_PACKET_SIZE) {
            modemPacketSize = DEFAULT_PER_PACKET_SIZE;
        }
        if (infoArray[i].type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            SetPerPacketSize(comHandle, DEFAULT_PER_PACKET_SIZE);
            SetIsReady(comHandle, false);
            ret = StartConnectSSB(i);
        } else {
            SetPerPacketSize(comHandle, modemPacketSize);
            ret = BurnOtherFile(i);
            SetIsReady(comHandle, false);
        }
        if (ret == FALSE) {
            BurnFileFailed();
            return false;
        }
        currentlyBurnSize += DataConvertor::Str2U32DecHex(infoArray[i].fileSize);
    }

    return true;
}

void BurnCtrl3XClass::BurnCtrl3X::StartConnectSub()
{
    if (infoArray.size() == 0) {
        QString log = tr("No files can be burned.\n");
        OutputString(log);
        return;
    }
    for (int i = 0; i < infoArray.size(); i++) {
        CreateSha256File(infoArray[i].path);
    }

    if (!InnerStartConnectSub()) {
        return;
    }

    RestConectSub();
}

BOOL BurnCtrl3XClass::BurnCtrl3X::StartConnectSSB(int index)
{
    BOOL ret = TRUE;
    QString ssbSha256FileName = Sha256File(infoArray[index].path);
    BIN_INFO smallSsbFileInfo = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB);
    QString fsbSha256FileName = Sha256File(smallSsbFileInfo.path);
    QString str = smallSsbFileInfo.path + "|" + fsbSha256FileName + "|" + "|" + "|";
    if (!smallSsbFileInfo.path.isEmpty()) {
        ret = StartBurnSsb(str);
    }
    if (ret == FALSE) {
        return FALSE;
    }
    BIN_INFO ssbAddKeyStory = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_ADD_KEYSTORE);
    BIN_INFO ssbAddCertificate = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_ADD_CERTIFICATE);
    BIN_INFO ssbSignature = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_SIGN_3321);
    str = infoArray[index].path + "|" + ssbSha256FileName + "|" + ssbAddKeyStory.path + "|" +
          ssbAddCertificate.path + "|" + ssbSignature.path;
    ret = StartBurnSsb(str);
    QString log = tr("Burn ") + currentlyBurnName + tr(" succeeded.\n");
    if (ret == TRUE) {
        OutputString(log);
    }
    return ret;
}

BOOL BurnCtrl3XClass::BurnCtrl3X::StartBurnSsb(const QString &str) const
{
    BOOL ret = BootDownload(comHandle, Global::QString2Gbk(str).data(), 0, 0, nullptr, nullptr);
    return ret;
}

void BurnCtrl3XClass::BurnCtrl3X::BurnFileFailed()
{
    mutex->lock();
    if (comHandle != 0) {
        DestroyDevice(comHandle);
        comHandle = 0;
        myCtrlMap.remove(comHandle);
    }
    mutex->unlock();
    currentlyBurnSize = 0;
    isOpen = false;
    QString log = tr("Burn ") + currentlyBurnName + tr(" failed.\n");
    OutputString(log);
    emit SignalBurnFileFailed();
    RemoveTempDir();
    if (isCancel == FALSE || !isMultipleBurn) {
        OneTimeBurnQuit(ERR_SELOADER_ACK_IS_FAIL);
    }
    if (isCancel == FALSE && isMultipleBurn) {
        Sleep(SLEEP_1S);
        InitBurnCmd();
        StartConnect();
    }
    return;
}

void BurnCtrl3XClass::BurnCtrl3X::RestConectSub()
{
    emit SignalSetProgressValue(SHRT_MAX);
    QTextStream qout(stdout);
    qout << "[" + QString::number(100) + "%]" << endl;  // 进度100%
    currentlyBurnName = "";
    currentlyBurnSize = 0;
    emit SignalBurnFileFinish();
    mutex->lock();
    if (comHandle != 0) {
        DestroyDevice(comHandle);
        comHandle = 0;
        myCtrlMap.remove(comHandle);
    }
    mutex->unlock();
    isOpen = false;
    OneTimeBurnQuit(0);
    RemoveTempDir();
    if (isMultipleBurn) {
        Sleep(SLEEP_1500);
        InitBurnCmd();
        StartConnect();
    }
}

void BurnCtrl3XClass::BurnCtrl3X::OneTimeBurnQuit(unsigned int result)
{
    SetResult(result);
    if (isOneTimeBurn != 0) {
        qDebug() << "isOneTimeBurn: " << isOneTimeBurn;
        Sleep(500); // 延迟500ms退出
        Global::CloseApp(this->result);
    }
}

int BurnCtrl3XClass::BurnCtrl3X::BurnOtherFile(int index)
{
    int ret = TRUE;
    IMAGE_TYPE infoType = infoArray[index].type;
    BIN_INFO signFileInfo;
    QString signFilePath = "";
    bool isBurn = true;
    int fileType = 0;
    if (infoType == IMAGE_TYPE::IMAGE_TYPE_APP_3321) {
        signFileInfo = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_APP_SIGN_3321);
        fileType = CORE_IMAGES_APPS;
    } else if (infoType == IMAGE_TYPE::IMAGE_TYPE_BT_3321) {
        signFileInfo = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_BT_SIGN_3321);
        fileType = CORE_IMAGES_BT;
    } else if (infoType == IMAGE_TYPE::IMAGE_TYPE_DSP_3321) {
        signFileInfo = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_DSP_SIGN_3321);
        fileType = CORE_IMAGES_PROTOCOL;
    } else if (infoType == IMAGE_TYPE::IMAGE_TYPE_DSP1_3321) {
        signFileInfo = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_DSP1_SIGN_3321);
        fileType = CORE_IMAGES_EXTERN0;
    } else if (infoType == IMAGE_TYPE::IMAGE_TYPE_FLASH_BIN_3321 ||
               infoType == IMAGE_TYPE::IMAGE_TYPE_EMMC_BIN_3321 ||
               infoType == IMAGE_TYPE::IMAGE_TYPE_OTP_BIN_3321) {
        signFilePath = Sha256File(infoArray[index].path);
        fileType = static_cast<int>(infoType);
    } else {
        isBurn = false;
    }
    if (isBurn) {
        SetIsFinalReset(index);
        if (chipType != ChipType::MELODY && signFilePath.isEmpty()) {
            signFilePath = Sha256File(infoArray[index].path);
        }
        qDebug() << "com:" << com << "LoadToFlash " << infoArray[index].path << " Start";
        ret = BurnOtherFileDownloadToFlash(signFilePath, fileType, index);
        if (ret == FALSE && isCancel == FALSE) {
            ret = BurnOtherFileDownloadToFlash(signFilePath, fileType, index);
        }
        qDebug() << "com:" << com << "LoadToFlash " << infoArray[index].path << " End";
        if (ret == TRUE) {
            QString log = tr("Burn ") + currentlyBurnName + tr(" succeeded.\n");
            OutputString(log);
        }
    }
    return ret;
}

int BurnCtrl3XClass::BurnCtrl3X::BurnOtherFileDownloadToFlash(const QString &signFilePath, int fileType, int index)
{
    QString str = infoArray[index].path;
    QString burnAddr = infoArray[index].burnAddr;
    QString burnSize = infoArray[index].burnSize;
    int ret = TRUE;
    if (signFilePath.isEmpty()) {
        ret = DownloadToFlash(comHandle, Global::QString2Gbk(str).data(), nullptr, nullptr,
                              DataConvertor::Str2U32DecHex(burnAddr), DataConvertor::Str2U32DecHex(burnSize),
                              0, fileType);
    } else {
        ret = DownloadToFlash(comHandle, Global::QString2Gbk(str + "|" + signFilePath).data(), nullptr, nullptr,
                              DataConvertor::Str2U32DecHex(burnAddr), DataConvertor::Str2U32DecHex(burnSize),
                              0, fileType);
    }
    SetIsReady(comHandle, true);
    return ret;
}

void BurnCtrl3XClass::BurnCtrl3X::SetIsFinalReset(int index) const
{
    if (!IsFinal(index) || (isMultipleBurn && (!isResetAfterSuccess))) {
        SetIsReset(comHandle, false);
    } else {
        SetIsReset(comHandle, true);
    }
}

bool BurnCtrl3XClass::BurnCtrl3X::IsFinal(int index) const
{
    int size = infoArray.size();
    for (int i = index + 1; i < size; i++) {
        IMAGE_TYPE infoType = infoArray[i].type;
        if (infoType == IMAGE_TYPE::IMAGE_TYPE_LOADER ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_APP_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_BT_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_DSP_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_DSP1_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_SMALL_SSB ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_FLASH_BIN_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_EMMC_BIN_3321 ||
            infoType == IMAGE_TYPE::IMAGE_TYPE_OTP_BIN_3321) {
            return false;
        }
    }
    return true;
}

QString BurnCtrl3XClass::BurnCtrl3X::Sha256File(QString fileName) const
{
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFile" +
                      "_" + QString::number(com);
    QFileInfo fileInfo(fileName);
    QString saveFile = saveDir + "/" + fileInfo.baseName() + "_sha256." + fileInfo.suffix();
    return saveFile;
}

void BurnCtrl3XClass::BurnCtrl3X::CreateSha256File(QString fileName) const
{
    QString cleanPath = QDir::cleanPath(fileName);
    if (cleanPath.isEmpty()) {
        return;
    }
    QFile f(cleanPath);
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFile" +
                      "_" + QString::number(com);
    QByteArray sha256;
    QFileInfo fileInfo(fileName);
    QString saveFile = saveDir + "/" + fileInfo.baseName() + "_sha256." + fileInfo.suffix();
    sha256.clear();
    if (f.open(QIODevice::ReadOnly)) {
        QCryptographicHash ch(QCryptographicHash::Sha256);
        if (ch.addData(&f)) {
            sha256 = ch.result();
        }
    }
    f.close();
    QFile sha256File(saveFile);
    if (sha256File.exists()) {
        sha256File.remove();
    }
    if (sha256File.open(QIODevice::WriteOnly)) {
        sha256File.write(sha256);
    }
    sha256File.close();
}

BIN_INFO BurnCtrl3XClass::BurnCtrl3X::FindSignFile(IMAGE_TYPE type)
{
    int i = 0;
    for (; i < infoArray.size(); i++) {
        if (infoArray[i].type == type) {
            break;
        }
    }
    if (i == infoArray.size()) {
        return BIN_INFO();
    }
    return infoArray[i];
}

void BurnCtrl3XClass::BurnCtrl3X::InitBurnCmd()
{
    InitBurnCmdByArray(infoArrayDlg);
}

void BurnCtrl3XClass::BurnCtrl3X::InnerInitBurnCmdByArray(const QMap<int, BIN_INFO> &infoArray,
    const QString &saveDir)
{
    for (auto it = infoArray.begin(); it != infoArray.end(); it++) {
        BIN_INFO info;
        QFileInfo fileInfo(it->path);
        QString strFileName;
        if (it->fileName.isEmpty()) {
            strFileName = fileInfo.fileName();
        } else {
            strFileName = it->fileName;
        }
        QString saveFile = saveDir + "/" + strFileName;
        QString cleanPath = QDir::cleanPath(it->path);
        if (cleanPath.isEmpty()) {
            continue;
        }
        QFile oldFile(cleanPath);
        QFile newFile(saveFile);
        if (!oldFile.open(QIODevice::ReadOnly)) {
            continue;
        }
        if (newFile.exists()) {
            newFile.remove();
        }
        if (!newFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            oldFile.close();
            continue;
        }
        oldFile.seek(DataConvertor::Str2U32DecHex(it->fileIndex));
        QByteArray fileText = oldFile.read(DataConvertor::Str2U32DecHex(it->fileSize));
        int ret = newFile.write(fileText);
        oldFile.close();
        newFile.close();
        if (ret == -1) {
            continue;
        }
        info = *it;
        info.path = saveFile;
        this->infoArray[it.key()] = info;
    }
}

void BurnCtrl3XClass::BurnCtrl3X::InitBurnCmdByArray(const QMap<int, BIN_INFO> &infoArray)
{
    if (com == -1) {
        return;
    }
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFile" + "_" + QString::number(com);
    QDir dir(saveDir);
    if (!dir.exists() && !dir.mkdir(saveDir)) {
        QString log = tr("Failed to create folder.\n");
        OutputString(log);
        return;
    }
    this->infoArray.clear();
    infoArrayDlg = infoArray;
    InnerInitBurnCmdByArray(infoArray, saveDir);
}

void BurnCtrl3XClass::BurnCtrl3X::SetTextEditReceivePrint(long long handle, const char* comNum,
    const char* szInfo, const char* deBugszInfo, BOOL flag)
{
    if (QString::fromLatin1(szInfo) == "#" || QString::fromLatin1(deBugszInfo) == "#") {
        return;
    }
    if (myCtrlMap.find(handle) != myCtrlMap.end() && myCtrlMap.value(handle) != nullptr) {
        QString log = QString::fromLatin1(szInfo) +"\n";
        myCtrlMap.value(handle)->OutputString(log);
        qDebug() <<__FUNCTION__<< "Info: " << QString::fromLatin1(szInfo) <<
                   " com" << QString::number(myCtrlMap.value(handle)->com);
        qDebug() <<__FUNCTION__<< "Debug: " << QString::fromLatin1(deBugszInfo) <<
                   " com" << QString::number(myCtrlMap.value(handle)->com);
    }
    Q_UNUSED(comNum);
    Q_UNUSED(flag);
}

void BurnCtrl3XClass::BurnCtrl3X::SetProgress(long long handle, int progress)
{
    auto it = myCtrlMap.find(handle);
    if (it != myCtrlMap.end() && myCtrlMap.value(handle) != nullptr) {
        if (it.value()->operatorType == OperatorType::OPERATOR_TYPE_BURN) {
            if (!it.value()->isBurnStart) {
                QString log = tr("Start burning ") + it.value()->currentlyBurnName + tr(".") + "\n";
                it.value()->OutputString(log);
                it.value()->isBurnStart = true;
                it.value()->SetResult(ERR_DOING);
            }
            int sumSize = 0;
            for (int i = 0; i < it.value()->infoArray.size(); i++) {
                sumSize += DataConvertor::Str2U32DecHex(it.value()->infoArray[i].fileSize);
            }
            double pos = ProgressValue(it.value(), progress, sumSize);
            QTextStream qout(stdout);
            qout << "[" + QString::number(pos / static_cast<double>(SHRT_MAX) * NUMBER_ONE_HUNDRED,
                                          'f', NUMBER_VALUE_TWO) + "%]" << endl;
            emit it.value()->SignalSetProgressValue(pos);
        } else if (it.value()->operatorType == OperatorType::OPERATOR_TYPE_ERASE_ALL) {
            double pos = (static_cast<double>(progress) / static_cast<double>(100)) * SHRT_MAX;
            emit it.value()->SignalSetProgressValue(pos);
            if (!it.value()->isBurnStart) {
                QString log = tr("SSB burning ...\n");
                it.value()->OutputString(log);
                it.value()->isBurnStart = true;
            }
        } else {
            double pos = (static_cast<double>(progress) / static_cast<double>(100)) * SHRT_MAX;
            emit it.value()->SignalSetProgressValue(pos);
            QTextStream qout(stdout);
            qout << "[" + QString::number(pos / static_cast<double>(SHRT_MAX) * NUMBER_ONE_HUNDRED,
                                          'f', NUMBER_VALUE_TWO) + "%]" << endl;
            if (!it.value()->isBurnStart) {
                QString log = tr("Export started.\n");
                it.value()->OutputString(log);
                it.value()->isBurnStart = true;
            }
        }
    }
}

double BurnCtrl3XClass::BurnCtrl3X::ProgressValue(BurnCtrl3X *&burnCtrl3X, int progress, int sumSize)
{
    double pos = 0.0;
    for (int i = 0; i < burnCtrl3X->infoArray.size(); i++) {
        if (burnCtrl3X->infoArray[i].fileName == burnCtrl3X->currentlyBurnName) {
            double burnSize = static_cast<double>(DataConvertor::Str2U32DecHex(burnCtrl3X->infoArray[i].fileSize)) *
                              static_cast<double>(progress) * 0.01;
            pos = ((static_cast<double>(burnSize) + static_cast<double>(burnCtrl3X->currentlyBurnSize)) /
                   static_cast<double>(sumSize)) * static_cast<double>(SHRT_MAX);
            break;
        }
    }
    return pos;
}

void BurnCtrl3XClass::BurnCtrl3X::BurnCtrlCancel()
{
    mutex->lock();
    if (comHandle != 0 && !comHandleMap.value(comHandle)) {
        Cancel(comHandle);
        comHandleMap.remove(comHandle);
    }
    mutex->unlock();
}

void BurnCtrl3XClass::BurnCtrl3X::OutputString(QString editStr)
{
    if (!isMultipleBurn) {
        InsertPlainText(editStr);
    }
}

void BurnCtrl3XClass::BurnCtrl3X::RemoveTempDir() const
{
    QString saveDir = QCoreApplication::applicationDirPath() + "/tempFile" + "_"
            + QString::number(com);
    QDir dir(saveDir);
    if (dir.exists()) {
        dir.removeRecursively();
    }
}

void BurnCtrl3XClass::BurnCtrl3X::ResetUIAndFSM()
{
    SlotKillAllTimer();
    UpdateProgress(0);
}

void BurnCtrl3XClass::BurnCtrl3X::SlotSetResult(WPARAM srcData)
{
    Q_UNUSED(srcData);
}

bool BurnCtrl3XClass::BurnCtrl3X::ConfigComPort()
{
    return true;
}

void BurnCtrl3XClass::BurnCtrl3X::SetResult(unsigned int result)
{
    if (!isFirstBurnStart && result == ERR_WAITING &&
        (this->result == 0 || (this->result != ERR_DOING))) {
        return;
    }
    isFirstBurnStart = false;
    this->result = result;
    AddLog(stringClass.GetIdsString32845() + QString::number(this->result));
    NotifyState(NOTIFY_TYPE_RESULT, this->result);
    if (independent) {
        ShowResult();
        return;
    }
}

void BurnCtrl3XClass::BurnCtrl3X::SlotExport(WPARAM data, LPARAM len)
{
    Q_UNUSED(len);
    if (com <= 0) {
        emit SignalOpenComFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        return;
    }
    SetChipType(0x30002);
    QString comStr = "COM" + QString::number(com);
    comHandle = OpenSerialPort(comStr.toLatin1(), baud, Global::Stopbits2Int(stopbits), Global::Parity2Int(parity));
    if (comHandle == 0) {
        emit SignalOpenComFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        return;
    }
    QString log = tr("Connecting...Reset the device...\r\n");
    OutputString(log);
    myCtrlMap.insert(comHandle, this);
    comHandleMap.insert(comHandle, false);
    isOpen = true;
    ExportInfo *info = reinterpret_cast<ExportInfo *>(data);
    operatorType = OperatorType::OPERATOR_TYPE_EXPORT;
    BOOL ret = UploadFile(comHandle, info->addr, info->len, Global::QString2Gbk(info->path).data());
    if (ret == FALSE) {
        Reset(comHandle);
        OutputString(IDS_STRING_32879 + "\n");
        OutputString(tr("Flash export failed.\n"));
        OutputString(IDS_STRING_32879 + "\n");
        mutex->lock();
        if (comHandle != 0) {
            DestroyDevice(comHandle);
            comHandle = 0;
        }
        mutex->unlock();
        currentlyBurnSize = 0;
        isBurnStart = false;
        isOpen = false;
        emit SignalExportfail();
        OneTimeBurnQuit(ERR_SELOADER_ACK_IS_FAIL);
        return;
    } else {
        ExportSuccess();
    }
    delete info;
}

void BurnCtrl3XClass::BurnCtrl3X::ExportSuccess()
{
    OutputString(IDS_STRING_32879 + "\n");
    OutputString(tr("Flash export succeeded.\n"));
    OutputString(IDS_STRING_32879 + "\n");
    mutex->lock();
    if (comHandle != 0) {
        DestroyDevice(comHandle);
        comHandle = 0;
    }
    mutex->unlock();
    isOpen = false;
    isBurnStart = false;
    currentlyBurnSize = 0;
    emit SignalExportSuccess();
    OneTimeBurnQuit(0);
}

void BurnCtrl3XClass::BurnCtrl3X::EraseAll()
{
    if (com <= 0) {
        emit SignalOpenComFail();
        emit SignalEraseFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        return;
    }
    SetChipType(0x30002);
    QString comStr = "COM" + QString::number(com);
    comHandle = OpenSerialPort(comStr.toLatin1(), 115200, Global::Stopbits2Int(stopbits), // 设置波特率为115200
                               Global::Parity2Int(parity));
    if (comHandle == 0) {
        emit SignalOpenComFail();
        emit SignalEraseFail();
        OneTimeBurnQuit(ERR_COM_INVALID);
        return;
    }
    SetIsReady(comHandle, true);
    for (int i = 0; i < infoArray.size(); i++) {
        CreateSha256File(infoArray[i].path);
    }
    operatorType = OperatorType::OPERATOR_TYPE_ERASE_ALL;
    myCtrlMap.insert(comHandle, this);
    OutputString(tr("Connecting...Reset the device...\r\n"));
    isBurnStart = false;
    for (auto it = infoArray.begin(); it != infoArray.end(); it++) {
        if (it->type == IMAGE_TYPE::IMAGE_TYPE_LOADER) {
            QString ssbSha256FileName = Sha256File(it.value().path);
            BIN_INFO ssbAddKeyStory = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_ADD_KEYSTORE);
            BIN_INFO ssbAddCertificate = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_ADD_CERTIFICATE);
            BIN_INFO ssbSignature = FindSignFile(IMAGE_TYPE::IMAGE_TYPE_SSB_SIGN_3321);
            QString strPath = it.value().path + "|" + ssbSha256FileName + "|" + ssbAddKeyStory.path + "|" +
                  ssbAddCertificate.path + "|" + ssbSignature.path;
            QByteArray array = Global::QString2Gbk(strPath);
            int retValue = EraseAllFlash(comHandle, array.data());
            if (retValue == FALSE) {
                EraseAllFail();
            } else {
                EraseAllSuccess();
            }
            return;
        }
    }
    if (EraseAllFlash(comHandle, nullptr) == FALSE) {
        EraseAllFail();
    } else {
        EraseAllSuccess();
    }
    myCtrlMap.remove(comHandle);
}

void BurnCtrl3XClass::BurnCtrl3X::EraseAllSuccess()
{
    OutputString(IDS_STRING_32879 + "\n");
    OutputString(tr("Flash erase succeeded.\n"));
    OutputString(IDS_STRING_32879 + "\n");
    EndInit();
    emit SignalEraseSuccess();
    OneTimeBurnQuit(0);
}

void BurnCtrl3XClass::BurnCtrl3X::EraseAllFail()
{
    OutputString(IDS_STRING_32879 + "\n");
    OutputString("Flash erase failed\n");
    OutputString(IDS_STRING_32879 + "\n");
    EndInit();
    emit SignalEraseFail();
    OneTimeBurnQuit(ERR_FAILURE);
}

void BurnCtrl3XClass::BurnCtrl3X::EndInit()
{
    mutex->lock();
    if (comHandle != 0) {
        DestroyDevice(comHandle);
        comHandle = 0;
        myCtrlMap.remove(comHandle);
    }
    mutex->unlock();
    currentlyBurnSize = 0;
    RemoveTempDir();
    isBurnStart = false;
}
